/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "client_trans_session_service.h"

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <unistd.h>

#include "client_qos_manager.h"
#include "client_trans_channel_manager.h"
#include "client_trans_file_listener.h"
#include "client_trans_session_manager.h"
#include "dfs_session.h"
#include "inner_session.h"
#include "securec.h"
#include "softbus_adapter_mem.h"
#include "softbus_adapter_timer.h"
#include "softbus_client_frame_manager.h"
#include "softbus_def.h"
#include "softbus_errcode.h"
#include "softbus_feature_config.h"
#include "softbus_json_utils.h"
#include "softbus_log.h"
#include "softbus_trans_def.h"
#include "softbus_utils.h"
#include "trans_server_proxy.h"

#include "los_task.h"
typedef struct {
    ListNode node;
    ConnectionAddr addr;
} JoinBleConnectItem;

typedef struct {
    ListNode joinBleConnectList;
    uint8_t joinBleConnectCount;
} BleConnectCenter;

#define MAX_CONNECTIONS 6
extern ConnectionAddr BleConDeviceAddr[MAX_CONNECTIONS];

static BleConnectCenter g_BlebusCenterClient = { 0 };
static char *g_deviceSessinName = NULL;
uint8_t g_transSessionFlag = -1;
char *TransSessionData = NULL;
uint8_t g_transSessionConnId = -1;
uint8_t g_transSessionDataLength = 0;

static int SetTransSessionData(char *data)
{
    if (data == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "set Trans Session data is NULL");
        return SOFTBUS_ERR;
    }

    TransSessionData = malloc(g_transSessionDataLength + 1);
    if (TransSessionData == NULL) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail: malloc join LNN cb list item");
        return SOFTBUS_MALLOC_ERR;
    }

    memset(TransSessionData, 0,  g_transSessionDataLength + 1);
    memcpy(TransSessionData, data, g_transSessionDataLength);

    return SOFTBUS_OK;
}

void TransSessionHandle(uint8_t conn_idx, uint8_t *data, uint8_t length)
{
    if (data == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "receive data is NULL");
        return;
    }

    if(BleConDeviceAddr[conn_idx].info.ble.role_type ==  GAP_LL_ROLE_SLAVE)
    {
        uint16_t dsoftbusFlag = BuildDsoftbusBleAdvFlag(&BleConDeviceAddr[conn_idx].info.ble.bleMac);
        //printf("dsoftbusFlag=%x\r\n", dsoftbusFlag);
        uint8_t highByte, lowByte;
        // 分解uint16_t到两个uint8_t  
        highByte = (uint8_t)(dsoftbusFlag >> 8); // 右移8位，取高8位  
        lowByte = (uint8_t)(dsoftbusFlag & 0xFF); // 与0xFF进行AND操作，取低8位
        printf("dsoftbusFlag:%2X%2X\r\n", highByte, lowByte);
        if(1 == BleConDeviceAddr[conn_idx].info.ble.Dsoftbusflags)
        {
            g_transSessionFlag = 1;
            g_transSessionConnId = conn_idx;
            g_transSessionDataLength = length;
            if (SetTransSessionData(data) != SOFTBUS_OK) {
                SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "SetTransSessionData error!");
                return;
            }
        }
        if(highByte == data[0] && lowByte == data[1])
        {
            printf("Check and verify succeed !!!\r\n");
            BleConDeviceAddr[conn_idx].info.ble.Dsoftbusflags = 1;
        }
    } else if(BleConDeviceAddr[conn_idx].info.ble.role_type ==  GAP_LL_ROLE_MASTER) {
        g_transSessionFlag = 1;
        g_transSessionConnId = conn_idx;
        g_transSessionDataLength = length;
        if (SetTransSessionData(data) != SOFTBUS_OK) {
            SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "SetTransSessionData error!");
            return;
        }
    }
}

static JoinBleConnectItem *FindJoinLNNCbItem(ConnectionAddr *addr)
{
    JoinBleConnectItem *item = NULL;

    LIST_FOR_EACH_ENTRY(item, &g_BlebusCenterClient.joinBleConnectList, JoinBleConnectItem, node) {
        //printf("%s: list.ConnectId %d, addr.ConnectId %d\n", __func__, item->addr.info.ble.ConnectId, addr->info.ble.ConnectId);
        if(item->addr.info.ble.ConnectId == addr->info.ble.ConnectId) {
            return item;
        }
    }
    return NULL;
}

static int32_t AddJoinBleConnectItem(ConnectionAddr *target)
{
    JoinBleConnectItem *item = NULL;

    item = (JoinBleConnectItem *)SoftBusMalloc(sizeof(*item));
    if (item == NULL) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail: malloc join LNN cb list item");
        return SOFTBUS_MALLOC_ERR;
    }

    ListInit(&item->node);
    item->addr = *target;

    ListAdd(&g_BlebusCenterClient.joinBleConnectList, &item->node);
    g_BlebusCenterClient.joinBleConnectCount++;
    return SOFTBUS_OK;
}

static int32_t DeleteJoinBleConnectItem(ConnectionAddr *target)
{
    JoinBleConnectItem *item = NULL;
    item = FindJoinLNNCbItem(target);
    if (item != NULL) {
        ListDelete(&item->node);
        SoftBusFree(item);
        g_BlebusCenterClient.joinBleConnectCount--;
        return SOFTBUS_OK;
    }

    return SOFTBUS_ERR;
}

static int32_t JoinBleConnectList(ConnectionAddr *target, ISessionListener *listener)
{
    if(target == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "Connection Addr is NULL");
        return SOFTBUS_ERR;
    }

    JoinBleConnectItem *item = NULL;
    if(item = FindJoinLNNCbItem(target) != NULL) {
        //SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "Sessionid is exists!");
        return SOFTBUS_ERR;
    }

    if (AddJoinBleConnectItem(target) != SOFTBUS_OK) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "Join a BLE connected device error!");
        return SOFTBUS_ERR;
    }

    //printf("%s: target->info.ble.ConnectId %d\n", __func__, target->info.ble.ConnectId);
    if(target->info.ble.ConnectId >= 0 && target->info.ble.ConnectId < 255) {
        if ((listener->OnSessionOpened == NULL) || (listener->OnSessionOpened(target->info.ble.ConnectId, SOFTBUS_OK) != SOFTBUS_OK)) {
            SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "OnSessionOpened failed");
            return SOFTBUS_ERR;
        }

        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_INFO, "TransOnSessionOpened ok");
    }

    return SOFTBUS_OK;
}

static int32_t DeleteBleConnectList(ConnectionAddr *target, ISessionListener *listener)
{
    if(target == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "Connection Addr is NULL");
        return SOFTBUS_ERR;
    }
    //printf("%s: target->info.ble.ConnectId %d\n", __func__, target->info.ble.ConnectId);
    JoinBleConnectItem *item = NULL;
    if(item = FindJoinLNNCbItem(target) == NULL) {
        //SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "Sessionid is null!");
        return SOFTBUS_ERR;
    }

    if (DeleteJoinBleConnectItem(target) != SOFTBUS_OK) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, " Delete a BLE connected device error!");
        return SOFTBUS_ERR;
    }

    //printf("%s: target->info.ble.ConnectId %d\n", __func__, target->info.ble.ConnectId);
    if(target->info.ble.ConnectId >= 0 && target->info.ble.ConnectId < 255) {
        if (listener->OnSessionClosed == NULL) {
            SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "OnSessionClosed failed");
            return SOFTBUS_ERR;
        }
        listener->OnSessionClosed(target->info.ble.ConnectId);
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_INFO, "TransOnSessionClosed ok");
    }

    return SOFTBUS_OK;
}

static int32_t BleTransSessionHandle(ISessionListener *listener)
{
    if (listener == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "listener is NULL");
        return SOFTBUS_ERR;
    }

    if (listener->OnBytesReceived == NULL) {
        SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "OnBytesReceived failed");
        return SOFTBUS_ERR;
    }

    listener->OnBytesReceived(g_transSessionConnId, TransSessionData, g_transSessionDataLength);
    SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_INFO, "TransOnBytesReceived ok");

    g_transSessionDataLength = 0;
    SoftBusFree(TransSessionData);
    return SOFTBUS_OK;
}
typedef struct MasterSend {
    int sendFlag;
    int connectId;
} MasterSend;


#define SEND_DATA_SIZE_5 5
char g_testData[3] = {0};
void SetDsoftbusFlage(void)
{
    char local_addr[6] = { 0 };
    GetLocalAddr(local_addr, 6);
    uint16_t dsoftbusFlag = BuildDsoftbusBleAdvFlag(&local_addr);
    //printf("%s: dsoftbusAdvFlag %x\n", __func__, dsoftbusFlag);
    uint8_t highByte, lowByte;  
    // 分解uint16_t到两个uint8_t  
    highByte = (uint8_t)(dsoftbusFlag >> 8); // 右移8位，取高8位  
    lowByte = (uint8_t)(dsoftbusFlag & 0xFF); // 与0xFF进行AND操作，取低8位

    char *testData = (char *)SoftBusCalloc(SEND_DATA_SIZE_5);
    if (testData == NULL) {
        printf("Failed to allocate memory for testData!\n");
        return;
    }
    testData[0] = highByte;
    testData[1] = lowByte;
    size_t dataLenToCopy = sizeof(g_testData);
    if (dataLenToCopy > SEND_DATA_SIZE_5) {
        printf("Data length to copy exceeds the buffer size!\n");
        free(testData);
        return;
    }
    if (memcpy_s(g_testData, dataLenToCopy, testData, 2)!= 0) {
        printf("memcpy_s g_testData failed!\n");
        free(testData);
        return;
    }
    free(testData); 
}

MasterSend mashtersend;
void BleSessionIdHandle(ISessionListener *listener)
{
    int32_t sconnect_handle = -1;
    int32_t mconnect_handle = -1;
    int32_t connect_id = -1;
    int32_t device_role = -1;

    ConnectionAddr BleAddr;

    int connectFlag = BleGetConnectFlag();
    //printf("%s: connectFlag %d\n", __func__, connectFlag);
    if(connectFlag == 1) {
        uint8_t BleConnectAddrLenth = app_connect_info_get(&device_role, &sconnect_handle, &mconnect_handle, &BleAddr.info.ble.bleMac);
        if(sconnect_handle != 0xff) {
            connect_id = sconnect_handle;
            BleAddr.info.ble.ConnectId = sconnect_handle;
            mashtersend.sendFlag = -1;
            mashtersend.connectId = sconnect_handle;
            SetDsoftbusFlage();
        } else if (mconnect_handle != 0xff) {
            connect_id = mconnect_handle;
            BleAddr.info.ble.ConnectId = mconnect_handle;
        }
        BleAddr.info.session.type = device_role;

        memcpy(BleConDeviceAddr[connect_id].info.ble.bleMac, BleAddr.info.ble.bleMac, sizeof(BleAddr.info.ble.bleMac));
        BleConDeviceAddr[connect_id].info.ble.Dsoftbusflags = -1;
        BleConDeviceAddr[connect_id].info.ble.ConnectId = connect_id;
        BleConDeviceAddr[connect_id].info.ble.role_type = device_role;


        JoinBleConnectList(&BleAddr, listener);
    } else if (connectFlag == -1){
        uint8_t disconnect_handle = app_disconnect_connid_get();
        //printf("%s: disconnect_handle %u\n", __func__, disconnect_handle);
        //BleAddr.info.ble.ConnectId = disconnect_handle;
        if (disconnect_handle < sizeof(BleConDeviceAddr) / sizeof(BleConDeviceAddr[0])) { // 检查数组越界
            BleConDeviceAddr[disconnect_handle].info.ble.ConnectId = disconnect_handle;
            //DeleteBleConnectList(&BleAddr, listener);
            DeleteBleConnectList(&BleConDeviceAddr[disconnect_handle], listener);
        }
    }

    if (g_transSessionFlag == 1 && g_transSessionFlag != -1) {
        if(mashtersend.sendFlag == -1) {
            LOS_TaskDelay(2000);
            int ret =SendBytes(mashtersend.connectId, g_testData, strlen(g_testData));
            if(ret == SOFTBUS_OK) {
                printf("sendBytes ok\r\n");
                mashtersend.sendFlag = 0;
            }
        }
        if (BleTransSessionHandle(listener) != SOFTBUS_OK) {
            g_transSessionFlag = -1;
        }
        g_transSessionFlag = 0;
    }
}

void SessionHandleTask()
{
    int connectNum = 0;
    while(1) {
        ISessionListener listener = {0};
        int32_t ret = ClientGetSessionCallbackByName(g_deviceSessinName, &listener);
        if (ret != SOFTBUS_OK) {
            SoftBusLog(SOFTBUS_LOG_TRAN, SOFTBUS_LOG_ERROR, "get session listener failed");
            return;
        }

        BleSessionIdHandle(&listener);
        LOS_TaskDelay(100);
    }
}

void SetDeviceSessionName(const char *sessionName)
{
    if (g_deviceSessinName != NULL) {  
        free(g_deviceSessinName);  
    }
  
    size_t length = strlen(sessionName) + 1;

    g_deviceSessinName = (char *)malloc(length);
    if (g_deviceSessinName == NULL) {
        return;
    }

    errno_t err = strcpy_s(g_deviceSessinName, length, sessionName);
    //printf("%s: g_deviceSessinName %s\n", __func__, g_deviceSessinName);
    if (err != 0) {
        free(g_deviceSessinName);
        g_deviceSessinName = NULL;
        return;
    }

}

void CreatSessionHandleTask()
{
    uint32_t taskId = 0;
    TSK_INIT_PARAM_S taskParam = {0};
    taskParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SessionHandleTask;
    taskParam.uwArg = 0;
    taskParam.uwStackSize = 1024 * 18;
    taskParam.pcName = "SessionHandleTask";
    taskParam.usTaskPrio = 20;

    int ret = LOS_TaskCreate(&taskId, &taskParam);
    if (ret != LOS_OK) {
        printf("ret of LOS_TaskCreate(HelloWorldTask) = %#x", ret);
    }
}

void BleConnectListInit()
{
    ListInit(&g_BlebusCenterClient.joinBleConnectList);
}
